package uabc.arduino.graficas;

import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Observable;
import java.util.Observer;

import javax.swing.JPanel;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.time.Millisecond;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;

import uabc.arduino.archivo.CsvManager;
import uabc.arduino.componentes.ChartConfiguration;
import uabc.arduino.componentes.ItemRendered;
import uabc.arduino.elementos.SerieConfiguration;
import uabc.arduino.enums.TipoGrafica;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;

import javax.swing.ImageIcon;

public class Grafica extends JPanel implements Observer {

	private String titulo;
	private String unidades;
	private ChartConfiguration chartConf;
	private XYPlot xyplot;
	private ArrayList<SerieConfiguration> series;
	private CsvManager csvManager;
	private boolean play;
	private boolean saveFile;

	/**
	 * @wbp.parser.constructor
	 */
	public Grafica(ChartConfiguration chartConf, CsvManager csvManager,
			boolean saveFile) {
		setBounds(100, 100, 630, 400);
		this.titulo = chartConf.getTitulo();
		this.unidades = chartConf.getUnidades();
		this.chartConf = chartConf;
		this.csvManager = csvManager;
		this.play = true;
		this.saveFile = saveFile;
		series = cloneList(chartConf.getConfiguraciones());
		TimeSeriesCollection timeseriescollection = new TimeSeriesCollection();
		for (SerieConfiguration c : series) {
			@SuppressWarnings("deprecation")
			TimeSeries serie = new TimeSeries(c.getNombre(), Millisecond.class);
			c.setSerie(serie);
			timeseriescollection.addSeries(serie);
		}
		setLayout(null);
		ChartPanel chartpanel = new ChartPanel(
				createChart(timeseriescollection));
		chartpanel.setBounds(15, 30, 600, 350);
		chartpanel.setPreferredSize(new Dimension(600, 350));
		this.add(chartpanel);

		JButton btnPausePlay = new JButton("");
		btnPausePlay.setIcon(new ImageIcon(Grafica.class
				.getResource("/uabc/arduino/recursos/play-pause.png")));
		btnPausePlay.setContentAreaFilled(false);
		btnPausePlay.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				play = !play;
			}
		});
		btnPausePlay.setBounds(15, 3, 35, 23);
		add(btnPausePlay);
		Font font = new Font("Tahoma", Font.BOLD, 12);
		BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
		FontMetrics fm = img.getGraphics().getFontMetrics(font);
		int xCount = 5;
		for (int i = 0; i < series.size(); i++) {
			ItemRendered chckbxVisible = new ItemRendered(series.get(i)
					.getNombre(), xyplot.getRenderer(), i);
			chckbxVisible.setBounds(xCount, 377,
					fm.stringWidth(series.get(i).getNombre()) + 25, 25);
			xCount += fm.stringWidth(series.get(i).getNombre()) + 30;
			add(chckbxVisible);
		}
	}

	public static ArrayList<SerieConfiguration> cloneList(
			ArrayList<SerieConfiguration> list) {
		ArrayList<SerieConfiguration> clone = new ArrayList<SerieConfiguration>(
				list.size());
		for (SerieConfiguration item : list)
			clone.add((SerieConfiguration) item.clone());
		return clone;
	}

	public Grafica(CsvManager csvManager) {
		setBounds(100, 100, 630, 400);

		ArrayList<String[]> data = csvManager.readerInfo();
		String[] encabezados = data.remove(0);
		this.titulo = encabezados[encabezados.length - 2];
		this.unidades = encabezados[encabezados.length - 1];
		int noSeries = encabezados.length - 4;
		TimeSeriesCollection timeseriescollection = new TimeSeriesCollection();
		TimeSeries[] series = new TimeSeries[noSeries];
		for (int i = 0; i < noSeries; i++) {
			series[i] = new TimeSeries(encabezados[i + 2], Millisecond.class);
			timeseriescollection.addSeries(series[i]);
		}
		for (String[] campo : data) {
			for (int i = 0; i < noSeries; i++) {
				series[i].addOrUpdate(new Millisecond(new Date(campo[0])),
						new Double(campo[i + 2]));
			}
		}

		setLayout(null);
		ChartPanel chartpanel = new ChartPanel(
				createChart(timeseriescollection));
		chartpanel.setBounds(15, 30, 600, 350);
		chartpanel.setPreferredSize(new Dimension(600, 350));

		Font font = new Font("Tahoma", Font.BOLD, 12);
		BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
		FontMetrics fm = img.getGraphics().getFontMetrics(font);
		// int width = fm.stringWidth("Your string");
		int xCount = 5;
		for (int i = 0; i < noSeries; i++) {
			ItemRendered chckbxVisible = new ItemRendered(encabezados[i + 2],
					xyplot.getRenderer(), i);
			chckbxVisible.setBounds(xCount, 377,
					fm.stringWidth(encabezados[i + 2]) + 25, 25);
			add(chckbxVisible);
			xCount += fm.stringWidth(encabezados[i + 2]) + 30;
		}
		this.add(chartpanel);
	}

	private JFreeChart createChart(XYDataset dataset) {
		JFreeChart jfreechart = ChartFactory.createTimeSeriesChart(titulo,
				"hh:mm:ss", unidades, dataset, true, true, true);
		xyplot = jfreechart.getXYPlot();
		ValueAxis valueaxis = xyplot.getDomainAxis();
		if (chartConf != null)
			if (chartConf.getTipo() == TipoGrafica.OSCILOSCOPIO)
				valueaxis.setFixedAutoRange(chartConf.getPeriodo());
		valueaxis = xyplot.getRangeAxis();
		valueaxis.setAutoRange(true);
		return jfreechart;
	}

	@Override
	public void update(Observable o, Object arg) {
		if (play) {
			try {
				String cadena = (String) arg;
				// System.out.println(cadena);
				if (cadena.startsWith("V:")) {
					cadena = cadena.substring(2);
					// System.out.println(cadena);
					HashMap<String, Double> valores = decodificar(cadena);
					String[] csv = new String[series.size() + 2];
					int count = 2;
					Millisecond millisecond = new Millisecond();
					csv[0] = (new Date().toString());
					csv[1] = new SimpleDateFormat("HH:mm:ss")
							.format(new Date());
					for (SerieConfiguration s : series) {
						double d = valores.get(s.getID());
						s.getSerie().add(millisecond, d);
						csv[count] = String.valueOf(d);
						count++;
					}
					// csv[count] = (new Date().toString());
					if (saveFile)
						csvManager.escribir(csv);
				}
			} catch (Exception e) {
				// System.err.println(e.toString());
			}
		}
	}

	public HashMap<String, Double> decodificar(String cadena) {
		String[] entradas = cadena.split("-");
		HashMap<String, Double> mapa = new HashMap<String, Double>();
		for (int i = 0; i < entradas.length; i++) {
			String[] entrada = entradas[i].split(":");
			mapa.put(entrada[0], Double.parseDouble(entrada[1]));
		}
		return mapa;
	}

	public void stop() {
		if (csvManager != null)
			csvManager.cerrar();
	}

	public String getUnidades() {
		return unidades;
	}

	public void setUnidades(String unidades) {
		this.unidades = unidades;
	}

	public ChartConfiguration getChartConf() {
		return chartConf;
	}

	public void setChartConf(ChartConfiguration chartConf) {
		this.chartConf = chartConf;
	}

	public CsvManager getCsvManager() {
		return csvManager;
	}

	public void setCsvManager(CsvManager csvManager) {
		this.csvManager = csvManager;
	}
}
